//
// Created by Administrator on 2024/7/5.
//

#ifndef UTILS_H
#define UTILS_H
#include <iomanip>
#include <sstream>
namespace protocol {
    typedef unsigned char byte;

    inline std::string toHex(const void *memory, const size_t size=1) {
        std::stringstream ss;
        const auto* ptr = static_cast<const byte*>(memory);
        ss << std::hex << std::uppercase << std::setfill('0');
        for(size_t i = 0; i < size; ++i) {
            ss << std::setw(2) << static_cast<int>(ptr[i]) << " ";
        }
        return ss.str();
    }

    inline byte* generateVersionFlag(const byte v1, const byte v2, const byte v3) {
        const auto version = new byte[3];
        version[0] = v1;
        version[1] = v2;
        version[2] = v3;
        return version;
    }

    typedef struct encrypt_option {
        uint32_t M1;
        uint32_t IA1;
        uint32_t IC1;
    } EncryptOption;

    inline byte* encrypt(const byte *buffer, const size_t size,uint32_t key, const EncryptOption& option) {
        const auto data = new byte[size];
        memcpy(data, buffer, size);
        if (0 == key)
            key = 1;
        auto mkey = option.M1;
        if (0 == mkey)
            mkey = 1;
        for (int idx = 0; idx < size; ++idx) {
            key = option.IA1 * (key % mkey) + option.IC1;
            data[idx] ^= static_cast<byte>((key >> 20) & 0xFF);
        }

        return data;
    }

    inline byte* decrypt(const byte *buffer, const size_t size, const uint32_t key, const EncryptOption& option) {
        return encrypt(buffer, size, key, option);
    }

    inline void dateTruncate(time_t &time) {
        const auto struct_time = localtime(&time);
        struct_time->tm_hour = struct_time->tm_min = struct_time->tm_sec = 0;
        time = mktime(struct_time);
    }

    inline std::string pointerToString(const char *data) {
        return std::string{data};
    }

    inline size_t getMsgIdPos() { return 9; }
}
#endif //UTILS_H
